/*****************************************************************************
文 件 名: gprs.c
描    述: GPRS相关操作模块，包括数据的接收、发送、协议处理
作    者: 武玉峰
版    本: 1.0
完成日期: 2016.8.19
修改历史: 
*****************************************************************************/
#include "gprs.h"
#include "usart.h"
#include "delay.h"
#include "string.h"
#include "rtc.h"
#include "timer.h"


 
u8        _UART1Buffer[RECEIVED_BUFFER_SIZE];
u16       _UART1BufferPosition;
extern u16       _TimeOutCount;
extern u8        _WorkPattern;
//当前的消息 
H4Message	 _H4Message;
H20Message   _H20Message; 
u16       _receivedHeadBytesDoneCount = 0;
u16       _receivedMessageBodyBytesDoneCount = 0;

 
//信号强度
u8  _SignalIntensity = 0;
//imei
u8         _IMEI[16];

 
//sim900是否已上电
//u8        _SIM_EN = 0;

//sim900发生错误标识
u8        _SIM900_ERR = 0;

//sim900发生错误次数
u8        _SIM900_ERR_SUM = 0;

//sim900当前的模式，0：命令模式，USART1发给sim900的数据被sim900当作AT命令处理
//                 1：数据模式，USART1发给sim900的数据被sim900当作数据处理，通过gprs发送给服务器
u8        _SIM900_MODE = 0;

//处理GPRS接收到的数据的循环队列
CircSeqQueue   _CirSeqQueue;


/*************************************************
函数名称: GetCRC
功    能: CRC校验函数
参    数: data1:要计算crc值的数据的地址
          len:  要计算crc值的数据的长度
返 回 值: 结算结果
*************************************************/
u16 GetCRC(u8 *data1, u8 len)
{
    u8 i;
    u16 reg_crc = 0xffff;

    while(len--)
    {
        reg_crc ^= *data1++;
        for (i = 0; i < 8; i++)
        {
            if (reg_crc & 0x01)
                reg_crc = (reg_crc >> 1) ^ 0x0a001;
            else
                reg_crc = reg_crc >> 1;
        }
    }
    return reg_crc;
}

/*************************************************
函数名称: QueueInitial
功    能: 循环队列初始化
参    数: 无           
返 回 值: 无
*************************************************/
void QueueInitial()
{

    memset(_CirSeqQueue.Elements, 0, sizeof(_CirSeqQueue.Elements));
    _CirSeqQueue.front = _CirSeqQueue.rear = 0;

}



/*************************************************
函数名称: DeQueue
功    能: 循环队列出队列操作
参    数: 返回值的地址           
返 回 值: 0 队列满 或队列为空  1 成功 
*************************************************/
char DeQueue(char * e)
{
 
	  if(_CirSeqQueue.front != _CirSeqQueue.rear)
		{
			*e = _CirSeqQueue.Elements[_CirSeqQueue.front];
			_CirSeqQueue.front = (_CirSeqQueue.front + 1) % QUEUE_SIZE; //队头指针后移
      return 1;
		}
		else
		{
			return 0;	 
		}
}


/*************************************************
函数名称: ParseHead
功    能: 解析收到的一个数据包
参    数: 无           
返 回 值: 无
*************************************************/
void ParseH20MessageHead()
{
    _H20Message.FirmwareVersion = _H20Message.HeadBodyData[0];
    _H20Message.ProtocolVersion = _H20Message.HeadBodyData[1];
   
     memcpy(_H20Message.IMEI, &_H20Message.HeadBodyData[2], 15); //IMEI号只有15个字节
    _H20Message.MessageType =  _H20Message.HeadBodyData[17];
    _H20Message.BodyLength = (_H20Message.HeadBodyData[18] << 8) + _H20Message.HeadBodyData[19];
}


/*************************************************
函数名称: PackHead
功    能: 将要发送的数据打包
参    数: 无           
返 回 值: 无
*************************************************/
void PackH20MessageHead()
{
    _H20Message.HeadBodyData[0] = _H20Message.FirmwareVersion;
    _H20Message.HeadBodyData[1] = _H20Message.ProtocolVersion;
     memcpy(&_H20Message.HeadBodyData[2], _H20Message.IMEI, 15);
    _H20Message.HeadBodyData[17] = _H20Message.MessageType;
    _H20Message.HeadBodyData[18] = (unsigned char)(_H20Message.BodyLength >> 8);
    _H20Message.HeadBodyData[19] = (unsigned char)(_H20Message.BodyLength & 0xff);
}

 
void ParseH4MessageHead()
{

	 
	  _H4Message.Version =	_H4Message.HeadBodyData[0];
		_H4Message.MessageType =	_H4Message.HeadBodyData[1];
		_H4Message.BodyLength = (_H4Message.HeadBodyData[2] << 8) + _H4Message.HeadBodyData[3];
 
}

void PackH4MSGHead()
{

  	 _H4Message.HeadBodyData[0]=	_H4Message.Version  ;	 
		_H4Message.HeadBodyData[1] = _H4Message.MessageType;	//类型
		_H4Message.HeadBodyData[2] = (unsigned char)(_H4Message.BodyLength >> 8); //消息体长度高字节
		_H4Message.HeadBodyData[3] = (unsigned char)(_H4Message.BodyLength & 0xff);//消息体长度低字节

}

void InitH4Message()
{
		_receivedHeadBytesDoneCount = 0;
		_receivedMessageBodyBytesDoneCount = 0;														 
		_H4Message.Version = 0;
		_H4Message.BodyLength = 0;
	  _H4Message.MessageType=0;
		memset(_H4Message.HeadBodyData,'\0',MSGH4_HEAD_LENGTH + MSGH4_BODY_BUFFER_SIZE); 
}
 
 

 /*************************************************
函数名称: BuildModbusMessage
功    能: 构建modbus数据包
参    数:  
返 回 值: 无
*************************************************/
void BuildModbusMessage( u8 address, u8 type, u16 start, u16 registers, u8 *message)
{
    //Array to receive CRC bytes:
    u16 crcbyte;

    message[0] = address;//地址
    message[1] = type;//功能码
    message[2] = (u8)(start >> 8);//起始地址高字节
    message[3] = (u8)start;//起始地址低字节
    message[4] = (u8)(registers >> 8);//读取点数高字节
    message[5] = (u8)registers;//读取点数低字节

    crcbyte = GetCRC(message, 6);
    message[6] = (u8)crcbyte;
    message[7] = (u8)(crcbyte >> 8);

}

 /*************************************************
函数名称: SendH20MsgToServerSync
功    能: 把类型为H20的消息同步发送到服务器，接收到服务器的响应之前会一直阻塞直到超时
参    数: data:要发送的数据的地址
          datalen：要发送的数据的长度
          timeout：超时时间，0.5秒为单位
         
返 回 值: 从服务器收到的消息
*************************************************/
H20Message * SendH20MsgToServerSync(H20Message * pHMessage,u16 timeout)
{
	  u16 j=0;
	  char   currentchar;
    u8* data=pHMessage->HeadBodyData;
	  u16 datalen= pHMessage->BodyLength+MSGH20_HEAD_LENGTH; 
	  PackH20MessageHead();
 		QueueInitial();
		_SIM900_MODE = 1;
	
	 DebugOut("\r\n"); 
		for(j=0;j<20;++j)					 
						DebugOut("%X ",data[j]); 
	  	 DebugOut("\r\n"); 
	  for(;j<datalen;++j)
	      DebugOut("%X ",data[j]); 
	DebugOut("\r\n"); 
	
	
    for(j = 0; j < datalen; ++j)
		{

				IWDG_Feed();
				CONLED = 0;
			 
				USART_SendData(USART1, data[j]);//向sim900发送数据
				while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET); //等待发送结束
				CONLED = 1;
		} 
		
		 InitH20Message();
			_TimeOutCount = 0;

			while(1)
			{	
					//处理从sim900收到的数据
					while( DeQueue(&currentchar)==1)
					{								
							  if (_receivedHeadBytesDoneCount < MSGH20_HEAD_LENGTH)
                {
                      _H20Message.HeadBodyData[_receivedHeadBytesDoneCount++] = currentchar;
                      if (_receivedHeadBytesDoneCount == MSGH20_HEAD_LENGTH)
                      {
													ParseH20MessageHead();
                          
													if (_H20Message.BodyLength == 0)
													{
													 
															return &_H20Message;
													}
													if (_H20Message.BodyLength > MSGH20_BODY_BUFFER_SIZE)
													{
															//_SYSERROR=1;
															 
													}

													 
											}
										
							   }
								 else
								 {


												_H20Message.HeadBodyData[MSGH20_HEAD_LENGTH+_receivedMessageBodyBytesDoneCount++] = currentchar;
												if (_receivedMessageBodyBytesDoneCount == _H20Message.BodyLength)
												{ 
														return &_H20Message; 
												}
							 	}
					}//while( DeQueue(&currentchar)==1)

					IWDG_Feed();
					if(_TimeOutCount > timeout)
							break;
			} 
			return 0;
}
H4Message * GetH4MessageBuffer()
{
	InitH4Message();
	return &_H4Message;
}
H20Message * GetH20MessageBuffer()
{
	InitH20Message();
	return &_H20Message;
}


 /*************************************************
函数名称: SendH4MsgToServerSync
功    能: 把类型为H4的消息同步发送到服务器，接收到服务器的响应之前会一直阻塞直到超时
参    数: data:要发送的数据的地址
          datalen：要发送的数据的长度
          timeout：超时时间，0.5秒为单位
          pHandleMessage:上层消息处理函数
返 回 值: 发送是否成功
*************************************************/
H4Message * SendH4MsgToServerSync(H4Message * pH4Message,u16 timeout)
{
	  u16     j=0;
	  char   currentchar;
	  u8 * data=(u8 *)pH4Message->HeadBodyData;
    u16 datalen=pH4Message->BodyLength + MSGH4_HEAD_LENGTH;
	  PackH4MSGHead();
	  QueueInitial();
	  _SIM900_MODE=1;
    for(j = 0; j < datalen; ++j)
		{

				IWDG_Feed();
				CONLED = 0;
			 
				USART_SendData(USART1, data[j]);//向sim900发送数据
				while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET); //等待发送结束
				CONLED = 1;
		} 
		InitH4Message();
		 
			_TimeOutCount = 0;

			while(1)
			{	
					//处理从sim900收到的数据
					while( DeQueue(&currentchar)==1)
					{								
							  if (_receivedHeadBytesDoneCount < MSGH4_HEAD_LENGTH)
                {
                      _H4Message.HeadBodyData[_receivedHeadBytesDoneCount++] = currentchar;
                      if (_receivedHeadBytesDoneCount == MSGH4_HEAD_LENGTH)
                      {
                          ParseH4MessageHead();
													if (_H4Message.BodyLength == 0)
													{
													 
															return 		&_H4Message;
													}
													if (_H4Message.BodyLength > MSGH4_BODY_BUFFER_SIZE)
													{
															//_SYSERROR=1;
															 
													}

												 
										}
									 
							}
							else
							{


							_H4Message.HeadBodyData[MSGH4_HEAD_LENGTH+_receivedMessageBodyBytesDoneCount++] = currentchar;
							if (_receivedMessageBodyBytesDoneCount == _H4Message.BodyLength)
							{
 

						   	 return 		&_H4Message;
								 
							}
						}
					}//while( DeQueue(&currentchar)==1)

					IWDG_Feed();
					if(_TimeOutCount > timeout)
							break;
			} 
			return 0;
}

 /*************************************************
函数名称: SendToServer
功    能: 把数据发送到服务器，发送完毕马上返回
参    数: data:要发送的数据的地址
          datalen：要发送的数据的长度
          timeout：超时时间，0.5秒为单位
返 回 值:  无
*************************************************/
void SendToServer(u8* data, u16 datalen,u16 timeout)
{
	  u16 j=0;
	  _SIM900_MODE=1;
	  QueueInitial();
    for(j = 0; j < datalen; ++j)
		{

				IWDG_Feed();
				CONLED = 0;
			 
				USART_SendData(USART1, data[j]);//向sim900发送数据
				while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET); //等待发送结束
				CONLED = 1;
		}  
}
 /*************************************************
函数名称: PrepareCommand
功    能: 准备执行AT命令
参    数: 无
返 回 值: 连接是否成功
*************************************************/
int PrepareCommand()
{
	 s16  i = 0;
    u32  u32Temp = 0;
     
    //LABEL1:
 
    _SIM900_MODE = 0;
   
    //_callreadyok=0;
  
    NETLED = 0;
    _TimeOutCount = 0;
    DelayHalfSecond(2);
    NETLED = 1; //连接灯灭
    DelayHalfSecond(2);
    NETLED = 0;
    DelayHalfSecond(2);
    NETLED = 1; //连接灯灭




		  if(STATUS == 0)
        {
            // 如果sim900关闭则打开
            printf("SIM900A POW ON ......!\r\n");
            SIM900POWER = 1;
           
           DelayHalfSecond(4);
            SIM900POWER = 0;
            
            _TimeOutCount = 0;
            DelayHalfSecond(6);
        }



    if(STATUS == 0)
    {
        _SIM900_ERR = 1;
        return 0;
    }

    printf("Begin to detect SIM900A netlight......\r\n");
    i = -1;
    _TimeOutCount = 0;
    u32Temp = 0;

		IWDG_Feed();
    while(1)
    {
        
        if(NETLIGHT == 0 )
        {
            //灭
            if(i == 1)
            {
                //开始计数
                _TimeOutCount = 0;
                i = 0;
            }
            CONLED = 1;
            NETLED = 1;

        }
        else
        {
            //亮

					IWDG_Feed();
            if(i == 0)
            {
                if(_TimeOutCount > 5)
                {
                    //灭300毫秒表示已注册到网络，这里用500*5=2500毫秒
                    break;
                }
                else
                {
                    i = 1;

                }

                u32Temp++;
                printf("NETLIGHT FLASH:%d\r\n", u32Temp);
            }
            else
            {
                i = 1;
            }

            CONLED = 0;
            NETLED = 0;

        }

        //if(_WorkPattern == 1)return -1;
        if(	u32Temp > 112)
        {
						_SIM900_ERR = 3;
            //闪烁112次后退出
            return 0;
        }
    }//while
		
    i = 0;
 
    DelayHalfSecond(2);
  start:      
        u32Temp = AT();
        if(u32Temp == 0)
        {
					  ++i;
            printf("AT command Err <:> \r\n");
            if(i==2)
						 CloseConnect();
						if(i==3)return 0;
				   	DelayHalfSecond(2);

  					goto start;
        }
				 

        printf("AT command OK\r\n");
				
				return 1;
 
}
 /*************************************************
函数名称: PrepareConnect
功    能: 准备建立sim900到服务器的连接
参    数: 无
返 回 值: 连接是否成功
*************************************************/
int PrepareConnect()
{

 
    u32  u32Temp = 0;
     
    //LABEL1:
    _SIM900_MODE = 0;
     if(PrepareCommand()==0)
			 return 0;

        //信号强度
        _SignalIntensity =  CSQ();
        printf("Signal intensity:%u\r\n", _SignalIntensity);



        //if(_WorkPattern == 1)return -1;
        NETLED = 0;
        _TimeOutCount = 0;
       DelayHalfSecond(2);
        u32Temp = CIPSHUT();  
        if(u32Temp == 0)
        {
            return 0;
        }
        NETLED = 1;
        printf("CIPSHUT command OK\r\n");





        //if(_WorkPattern == 1)return -1;
        NETLED = 0;
        _TimeOutCount = 0;
       DelayHalfSecond(2);
        NETLED = 1;

        //打开流控制
        u32Temp = IFC();
        if(u32Temp == 0)
        {
            return 0;
        }
        printf("IFC command OK\r\n");


        //if(_WorkPattern == 1)return -1;
        NETLED = 0;
       DelayHalfSecond(2);
        NETLED = 1;
        //获取状态
        u32Temp = CIPSTATUS();
        if(u32Temp != IP_INITIAL)
        {
            return 0;
        }
        printf("CIPSTATUS command OK\r\n");




        //if(_WorkPattern == 1)return -1;
        NETLED = 0;
        DelayHalfSecond(2);
        NETLED = 1;
        //透明传输
        u32Temp = CIPMODE();
        if(u32Temp == 0)
        {
            return 0;
        }
        printf("CIPMODE command OK\r\n");

        //if(_WorkPattern == 1)return -1;
        NETLED = 0;
        DelayHalfSecond(2);
        NETLED = 1;
        //获取IMEI号
        u32Temp = GetIMEI();
        if(u32Temp == 0)
        {
            return 0;
        }
        printf("GetIMEI command OK:%s\r\n", _IMEI);
        return 1;


}
 /*************************************************
函数名称: CloseConnect
功    能: 关闭sim900到服务器的连接
参    数: 无
返 回 值: 关闭是否成功
*************************************************/
u8 CloseConnect(void)
{
		u8 result=0;
	 //退出透明传输
		delay_ms(1000);
		USART_SendData(USART1, '+');//向串口1发送数据
		while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET); //等待发送结束
		USART_SendData(USART1, '+');//向串口1发送数据
		while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET); //等待发送结束
		USART_SendData(USART1, '+');//向串口1发送数据
		while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET); //等待发送结束
		delay_ms(500);
 
		_SIM900_MODE = 0;


		result = CIPSHUT();

		return result; 
}



 /*************************************************
函数名称: GPRSInit
功    能: 初始化gprs用到的相关变量
参    数: 无
返 回 值: 无
*************************************************/
void InitH20Message(void)
{
	
	  
  
    _H20Message.FirmwareVersion = 0;
	  _H20Message.ProtocolVersion=0;
    _H20Message.BodyLength = 0;
	  _H20Message.MessageType=0;
	 
    _receivedHeadBytesDoneCount = 0;
    _receivedMessageBodyBytesDoneCount = 0;
    memset(_H20Message.HeadBodyData, '\0', MSGH20_HEAD_LENGTH + MSGH20_BODY_BUFFER_SIZE);
	  memset(_H20Message.IMEI, '\0', 15);

}




 /*************************************************
函数名称: GprsProcess
功    能: 处理USART1中断收到的每个字节，sim900通过USART1与stm32通讯
参    数: 无
返 回 值: 无
*************************************************/
void GprsProcess(u8 Res)
{
        if(_SIM900_MODE == 0)
        {
            //命令模式
            _UART1Buffer[_UART1BufferPosition] = Res;
            _UART1BufferPosition++;

        }
        else
        {
					  //printf("%X ",Res);
            //数据模式
            if((_CirSeqQueue.rear + 1) % QUEUE_SIZE == _CirSeqQueue.front)
            {
							 //队列满了
               _SIM900_ERR=4;
            }
            else
            {
  							_CirSeqQueue.Elements[_CirSeqQueue.rear] = Res;
                _CirSeqQueue.rear = (_CirSeqQueue.rear + 1) % QUEUE_SIZE; //队尾指针后移
            }
        }



}

